using System;
using System.Security.Cryptography;
using System.Configuration;

namespace CCSService_WebRole
{
    /// <summary>
    /// Implements the licensing server.
    /// </summary>
    public class LicenseServer
    {
        /// <summary>
        /// Crypto API provider type to use for license key operations
        /// </summary>
        private static readonly int CRYPTO_PROVIDER_TYPE = 1;

        /// <summary>
        /// Crypto API provider name to use for license key operations
        /// </summary>
        private static readonly string CRYPTO_PROVIDER_NAME =
            "Microsoft Strong Cryptographic Provider";

        /// <summary>
        /// Default constructor 
        /// </summary>
        public LicenseServer()
        {
        }

        /// <summary>
        /// Build the string to use as the license key Crypto API container name
        /// for the specified product. 
        /// </summary>
        /// <param name="productName">Product string name</param>
        /// <returns>Appropriate container name to use for this product</returns>
        private string GetLicenseKeyContainerName(string productName)
        {
            return "LicenseKey" + productName;
        }

        /// <summary>
        /// Acquire the license keys for the specified product
        /// </summary>
        /// <param name="productName">Product string name</param>
        /// <returns>Provider context for the server private key</returns>
        private RSACryptoServiceProvider GetLicenseKeys(string productName)
        {
            // Initialize the RSA crypto provider
            CspParameters cspParameters = new CspParameters(
                CRYPTO_PROVIDER_TYPE,
                CRYPTO_PROVIDER_NAME,
                GetLicenseKeyContainerName(productName));

            // Use Local Machine keys (rather than storing the license key in 
            // the current user's profile for example)
            try
            {
                OperatingSystem os = Environment.OSVersion;
                Version vs = os.Version;
                if (vs.Major == 5 && vs.Minor == 1)
                {
                    cspParameters.Flags = System.Security.Cryptography.CspProviderFlags.UseDefaultKeyContainer;
                }
                else if (vs.Major == 5 && vs.Minor == 2)
                {
                    cspParameters.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
                }
            }
            catch
            {
                cspParameters.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
            }

            RSACryptoServiceProvider rsa;

            try
            {
                // Create the provider context with a key pair
                rsa = new RSACryptoServiceProvider(1024, cspParameters);
            }
            catch (System.Security.Cryptography.CryptographicException cEx)
            {
                System.Diagnostics.Debug.Write(cEx.Message);
                cspParameters.Flags = System.Security.Cryptography.CspProviderFlags.UseDefaultKeyContainer;
                // Create the provider context with a key pair
                rsa = new RSACryptoServiceProvider(1024, cspParameters);

            }

            rsa.PersistKeyInCsp = true;
            return rsa;

        }

        /// <summary>
        /// Initialize the licensing server for a new product.  The output 
        /// public key must get built into the actual binary for the specified
        /// product.  
        ///
        /// The output private key should be archived in a secure place other 
        /// than the harddisk of the license server. 
        /// </summary>
        /// <param name="productName">Product string name</param>
        /// <param name="publicKey">Server public key</param>
        /// <param name="privateKeyToArchive">Server private key</param>
        public void CreateNewProduct(
            string productName,
            out string publicKey)
        {
            // Initialize the key provider for this product
            RSACryptoServiceProvider rsa = this.GetLicenseKeys(productName);

            // Export just the public key for inclusion in the client
            publicKey = rsa.ToXmlString(false);

            rsa.Clear();
        }

        /// <summary>
        /// Recover a lost key due to disk crash, etc. 
        /// </summary>
        /// <param name="productName">Product string name</param>
        /// <param name="privateKeyFromArchive">Server private key</param>
        public void RecoverLicenseKey(
            string productName,
            string privateKeyFromArchive)
        {
            // Initialize the key provider for this product
            RSACryptoServiceProvider rsa = this.GetLicenseKeys(productName);

            // Import the private key
            rsa.FromXmlString(privateKeyFromArchive);
        }

        /// <summary>
        /// Prepare an authenticated license to be sent back to the requesting 
        /// client.   
        /// </summary>
        /// <param name="request">License request object</param>
        /// <returns>License response object</returns>
        public LicenseResponse CreateLicenseReponse(
            License request)
        {
            LicenseResponse response = new LicenseResponse();


            response.Initialize(
                request,
                GetLicenseKeys(request.Product));

            return response;
        }
    }
}